namespace HZY.Framework.Core.Aop.Attributes;

/// <summary>
/// 耗时统计
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class TimeAttribute : AopMoAttribute
{
    /// <summary>
    /// 定义事件拦截器
    /// </summary>
    public static List<Action<TimeContext, string>> TimeEvents { get; } = new List<Action<TimeContext, string>>();

    /// <summary>
    /// 备注/描述
    /// </summary>
    public string Remark { get; set; }

    /// <summary>
    /// 耗时统计
    /// </summary>
    /// <param name="remark">备注/描述</param>
    public TimeAttribute(string remark)
    {
        Remark = remark;
    }

    /// <summary>
    /// 方法执行前
    /// </summary>
    /// <param name="context"></param>
    public override void OnEntry(MethodContext context)
    {
        var stopwatch = new Stopwatch();
        //记录 api 执行耗时
        stopwatch.Restart();
        // 传递统计耗时对象
        context.Datas["Stopwatch"] = stopwatch;
        // 开始时间
        context.Datas["StartTime"] = DateTime.Now;
    }

    /// <summary>
    /// 方法执行异常
    /// </summary>
    /// <param name="context"></param>
    public override void OnException(MethodContext context)
    {

    }

    /// <summary>
    /// 方法执行成功后
    /// </summary>
    /// <param name="context"></param>
    public override void OnSuccess(MethodContext context)
    {

    }

    /// <summary>
    /// 获取日志文本
    /// </summary>
    /// <param name="context"></param>
    /// <param name="timeContext"></param>
    /// <returns></returns>
    protected virtual string GetLogText(MethodContext context, TimeContext timeContext)
    {
        var log = @$"
== 开始~结束时间：{timeContext.StartTime:yyyy-MM-dd HH:mm:ss.fff} ~ {timeContext.EndTime:yyyy-MM-dd HH:mm:ss.fff}
== 描述：        {Remark}
== 命名空间：     {timeContext.NameSpace} 
== 类名：        {timeContext.ClassName}
== 方法：        {timeContext.ReturnTypeName} {timeContext.MethodName}({(timeContext.ParameterStr is not null ? string.Join(",", timeContext.ParameterStr) : "")}) {{ ... }}
== 入参：        {(timeContext.ParameterValue is not null ? string.Join(",", timeContext.ParameterValue) : "")}
== 返回值：      {timeContext.ReturnValue}
== 耗时：        {timeContext.ElapsedMilliseconds} 毫秒! = {timeContext.ElapsedMilliseconds / 1000} 秒!
";

        return log;
    }

    /// <summary>
    /// 方法退出时，不论方法执行成功还是异常，都会执行
    /// </summary>
    /// <param name="context"></param>
    public override void OnExit(MethodContext context)
    {
        // 获取参数
        var stopwatch = context.Datas["Stopwatch"] as Stopwatch;

        if (stopwatch != null)
        {
            stopwatch.Stop();
            var endTime = DateTime.Now;

            // 获取日志对象
            var logger = GetLogger<TimeAttribute>(context);

            if (logger != null)
            {
                // 对象
                var timeContext = TimeContext.Map(context, Remark, stopwatch, endTime);

                var log = @$"
=========================方法执行 [耗时统计] 开始=========================
==
";

                log += GetLogText(context, timeContext);

                log += @$"
==
=========================方法执行 [耗时统计] 结束=========================
";

                logger.LogWarning(log);

                // 调用事件
                foreach (var item in TimeEvents)
                {
                    item.Invoke(timeContext, log);
                }
            }
        }

        base.OnExit(context);
    }
}